package com.flowable.service.impl;

import com.alibaba.fastjson.JSON;
import com.flowable.entity.TaskApprovalDTO;
import com.flowable.entity.TaskDTO;
import com.flowable.service.FlowableService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class FlowableServiceImpl implements FlowableService {

    /** 员工角色ID */
    private static final String EMPLOYEE_ROLE = "员工";
    /** 组长角色ID */
    private static final String TEAM_LEADER_ROLE = "组长";
    /** 经理角色ID */
    private static final String MANAGER_ROLE = "经理";

    /** 流程变量 - 员工任务分配 */
    private static final String VAR_LEAVE_TASK = "leaveTask";
    /** 流程变量 - 组长任务分配 */
    private static final String VAR_TEAM_LEADER_TASK = "zuzhangTask";
    /** 流程变量 - 经理任务分配 */
    private static final String VAR_MANAGER_TASK = "manageTask";
    /** 流程变量 - 审批结果 */
    private static final String VAR_CHECK_RESULT = "checkResult";
    /** 流程变量 - 请假人姓名 */
    private static final String VAR_LEAVE_NAME = "name";
    /** 流程变量 - 请假原因 */
    private static final String VAR_LEAVE_REASON = "reason";
    /** 流程变量 - 请假天数 */
    private static final String VAR_LEAVE_DAYS = "days";
    /** 流程变量 - 重试次数 */
    private static final String VAR_RETRY_COUNT = "retryCount";
    /** 审批结果 - 同意 */
    private static final String CHECK_RESULT_AGREE = "agree";
    /** 审批结果 - 拒绝 */
    private static final String CHECK_RESULT_REFUSE = "refuse";
    /** 最大重试次数 */
    private static final int MAX_RETRY_COUNT = 3;


    private final RuntimeService runtimeService;
    private final TaskService taskService;
    // 管理流程定义和部署，如部署BPMN文件、查询流程定义等
    private final RepositoryService repositoryService;
    // 提供历史数据查询，如已完成流程实例、活动实例、任务等
    private final HistoryService historyService;
    // 提供引擎管理和维护操作，如作业管理、数据库操作等
    private final ManagementService managementService;

    @Autowired
    public FlowableServiceImpl(RuntimeService runtimeService, TaskService taskService, RepositoryService repositoryService, HistoryService historyService, ManagementService managementService) {
        this.runtimeService = runtimeService;
        this.taskService = taskService;
        this.repositoryService = repositoryService;
        this.historyService = historyService;
        this.managementService = managementService;
    }

    @Override
    public String createFlowable(TaskDTO taskDTO) {
        String jsonString = JSON.toJSONString(taskDTO);
        Map<String,Object> variables = JSON.parseObject(jsonString, Map.class);
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(
                "ask_for_leave",
                variables
        );
        if (instance == null || instance.getId() == null) {
            throw new RuntimeException("流程启动失败，未返回有效流程实例");
        }
        log.info("请假流程已启动，流程ID：{}，申请人：{}，天数：{}，原因：{}",
                instance.getId(), taskDTO.getName(), taskDTO.getDays(), taskDTO.getReason());

        Task employeeTask = getUniqueTask(instance.getId(), EMPLOYEE_ROLE, "请假");
        employeeSubmitApplication(employeeTask.getId());

        return "流程创建成功:"+instance.getId();
    }


    @Override
    public String agreeLeaderFlowable(TaskApprovalDTO taskApprovalDTO) {
        // 验证任务存在且分配给正确角色
        Task task = validateTaskExists(taskApprovalDTO.getTaskId(), TEAM_LEADER_ROLE);
        // 设置审批结果变量
        Map<String, Object> variables = new HashMap<>();
        variables.put(VAR_CHECK_RESULT, taskApprovalDTO.getIsAgree() ? CHECK_RESULT_AGREE : CHECK_RESULT_REFUSE);
        variables.put("comment", taskApprovalDTO.getComment());
        // 如果通过，设置下一审批人
        if (taskApprovalDTO.getIsAgree()) {
            variables.put(VAR_MANAGER_TASK, MANAGER_ROLE);
        }
        // 完成任务
        taskService.complete(taskApprovalDTO.getTaskId(), variables);
        log.info("组长[{}]已{}请假申请，任务ID：{}，意见：{}",
                TEAM_LEADER_ROLE, taskApprovalDTO.getIsAgree() ? "通过" : "拒绝", taskApprovalDTO.getTaskId(), taskApprovalDTO.getComment());
        return "组长:"+taskApprovalDTO.getComment();
    }

    @Override
    public String agreeMangerFlowable(TaskApprovalDTO taskApprovalDTO) {
        // 验证任务存在且分配给正确角色
        Task task = validateTaskExists(taskApprovalDTO.getTaskId(), MANAGER_ROLE);

        // 设置审批结果变量
        Map<String, Object> variables = new HashMap<>();
        variables.put(VAR_CHECK_RESULT, taskApprovalDTO.getIsAgree() ? CHECK_RESULT_AGREE : CHECK_RESULT_REFUSE);
        variables.put("comment", taskApprovalDTO.getComment());

        // 完成任务
        taskService.complete(taskApprovalDTO.getTaskId(), variables);
        log.info("经理[{}]已{}请假申请，任务ID：{}，意见：{}",
                MANAGER_ROLE, taskApprovalDTO.getIsAgree() ? "通过" : "拒绝", taskApprovalDTO.getTaskId(), taskApprovalDTO.getComment());

        // 如果拒绝，验证流程是否正常结束
        if (!taskApprovalDTO.getIsAgree()) {
            verifyProcessEndStatus(task.getProcessInstanceId());
        }
        return "经理:"+taskApprovalDTO.getComment();
    }

    @Override
    public List<Map<String, Object>> getTasksByAssignee(String assignee) {
      return taskService.createTaskQuery()
                .taskAssignee(assignee)
                .orderByTaskCreateTime().desc()
                .list()
                .stream()
                .map(this::convertTaskToMap)
                .collect(Collectors.toList());
    }





    /**
     * 验证流程结束状态
     * @param processInstanceId 流程实例ID
     */
    private void verifyProcessEndStatus(String processInstanceId) {
        HistoricProcessInstance historicInstance = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        if (historicInstance != null && historicInstance.getEndTime() != null) {
            log.info("流程已正常结束，结束时间：{}", formatDate(historicInstance.getEndTime()));
        } else {
            log.error("流程未正确终止！当前状态：{}", getProcessStatus(processInstanceId));
            throw new IllegalStateException("流程未正确终止");
        }
    }

    /**
     * 获取流程当前状态
     * @param processInstanceId 流程实例ID
     * @return "进行中"或"已结束"
     */
    public String getProcessStatus(String processInstanceId) {
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        return instance == null ? "已结束" : "进行中";
    }

    /**
     * 格式化日期
     * @param date 日期对象
     * @return 格式化后的日期字符串
     */
    private String formatDate(Date date) {
        return date != null ?
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date) :
                "无记录";
    }


    /**
     * 员工提交请假申请
     * @param taskId 任务ID
     * @throws IllegalStateException 任务不存在或已完成时抛出
     */
    public void employeeSubmitApplication(String taskId) {
        try {
            // 验证任务存在且分配给正确角色
            Task task = validateTaskExists(taskId, EMPLOYEE_ROLE);

            // 设置流程变量
            Map<String, Object> variables = new HashMap<>();
            variables.put(VAR_TEAM_LEADER_TASK, TEAM_LEADER_ROLE);

            // 完成任务
            taskService.complete(taskId, variables);
            log.info("员工[{}]已提交请假申请，任务ID：{}", EMPLOYEE_ROLE, taskId);
        } catch (Exception e) {
            log.error("员工提交申请失败，任务ID：{}，错误：{}", taskId, e.getMessage());
            throw e;
        }
    }

    /**
     * 重新提交请假申请
     * @param taskId 任务ID
     * @param newReason 新的请假原因
     * @param newDays 新的请假天数
     * @throws IllegalStateException 任务不存在或已完成时抛出
     * @throws RuntimeException 超过最大重试次数时抛出
     */
    public void resubmitLeaveApplication(String taskId, String newReason, int newDays) {
        try {
            // 验证任务存在且分配给正确角色
            Task task = validateTaskExists(taskId, EMPLOYEE_ROLE);

            // 获取并更新重试次数
            Integer retryCount = (Integer) taskService.getVariable(taskId, VAR_RETRY_COUNT);
            retryCount = retryCount != null ? retryCount + 1 : 1;

            // 检查是否超过最大重试次数
            if (retryCount > MAX_RETRY_COUNT) {
                throw new RuntimeException("超过最大重试次数(" + MAX_RETRY_COUNT + ")");
            }

            // 设置流程变量
            Map<String, Object> variables = new HashMap<>();
            variables.put(VAR_LEAVE_REASON, newReason);
            variables.put(VAR_LEAVE_DAYS, newDays);
            variables.put(VAR_RETRY_COUNT, retryCount);
            variables.put(VAR_TEAM_LEADER_TASK, TEAM_LEADER_ROLE);

            // 完成任务
            taskService.complete(taskId, variables);
            log.info("员工[{}]已重新提交请假申请，任务ID：{}，重试次数：{}",
                    EMPLOYEE_ROLE, taskId, retryCount);
        } catch (Exception e) {
            log.error("重新提交申请失败，任务ID：{}，错误：{}", taskId, e.getMessage());
            throw e;
        }
    }


    /**
     * 验证任务存在且分配给正确角色
     * @param taskId 任务ID
     * @param expectedAssignee 预期处理人
     * @return 验证通过的任务
     * @throws IllegalStateException 任务不存在或处理人不匹配时抛出
     */
    private Task validateTaskExists(String taskId, String expectedAssignee) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new IllegalStateException("任务不存在: " + taskId);
        }
        if (!expectedAssignee.equals(task.getAssignee())) {
            throw new IllegalStateException("任务处理人不匹配，期望: " + expectedAssignee + "，实际: " + task.getAssignee());
        }
        return task;
    }


    /**
     * 获取唯一的任务（按流程实例ID、处理人和任务名称）
     * @param processInstanceId 流程实例ID
     * @param assignee 处理人
     * @param taskName 任务名称
     * @return 匹配的任务
     * @throws IllegalStateException 未找到任务或找到多个任务时抛出
     */
    private Task getUniqueTask(String processInstanceId, String assignee, String taskName) {
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .taskName(taskName)
                .orderByTaskCreateTime().desc()
                .list();

        if (tasks.isEmpty()) {
            throw new IllegalStateException("未找到" + assignee + "的[" + taskName + "]任务");
        }

        if (tasks.size() > 1) {
            log.warn("发现多个{}任务，将选择最新的: {}", taskName, tasks.stream()
                    .map(t -> t.getId() + "(" + t.getCreateTime() + ")")
                    .collect(Collectors.joining(", ")));
        }

        return tasks.get(0);
    }



    /**
     * 转换任务为Map
     * @param task 任务
     * @return 包含任务信息的Map
     */
    private Map<String, Object> convertTaskToMap(Task task) {
        Map<String, Object> taskInfo = new LinkedHashMap<>();
        taskInfo.put("taskId", task.getId());
        taskInfo.put("taskName", task.getName());
        taskInfo.put("processInstanceId", task.getProcessInstanceId());
        taskInfo.put("createTime", formatDate(task.getCreateTime()));

        // 添加流程变量信息
        Map<String, Object> variables = taskService.getVariables(task.getId());
        taskInfo.put("applicant", variables.get(VAR_LEAVE_NAME));
        taskInfo.put("leaveReason", variables.get(VAR_LEAVE_REASON));
        taskInfo.put("leaveDays", variables.get(VAR_LEAVE_DAYS));
        taskInfo.put("retryCount", variables.get(VAR_RETRY_COUNT));
        taskInfo.put("status", getProcessStatus(task.getProcessInstanceId()));

        return taskInfo;
    }



}
